package com.violet.constlib.exception;

import android.content.Context;

import com.violet.constlib.NetUtil;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ConnectException;
import java.net.UnknownHostException;
import java.util.List;

import retrofit2.HttpException;

/**
 * @author: shalei
 * @since: 2020/7/16 3:40 PM
 * @Desc:
 **/
public class ExceptionHandle {

    public static ResponeThrowable handleException(Throwable e, Context context) {
        ResponeThrowable ex;
        if (e instanceof ServerException) {
            ServerException resultException = (ServerException) e;
            ex = new ResponeThrowable("服务器异常", resultException, resultException.code);
            return ex;
        } else if (e instanceof ConnectException) {
            ex = new ResponeThrowable("连接失败", e, ERROR.NETWORD_ERROR);
            return ex;
        } else if (e instanceof javax.net.ssl.SSLHandshakeException) {
            ex = new ResponeThrowable("证书验证失败", e, ERROR.SSL_ERROR);
            return ex;
        } else if (e instanceof com.google.gson.stream.MalformedJsonException) {
            ex = new ResponeThrowable("数据解析错误", e, ERROR.PARSE_ERROR);
            return ex;
        } else if(e instanceof NumberFormatException) {
            ex = new ResponeThrowable("数据解析错误", e, ERROR.PARSE_ERROR);
            return ex;
        } else if(e instanceof HttpException) {
            if(!NetUtil.isNetworkConnected(context)) { //本地不通
                ex = new ResponeThrowable("请检查你的网络是否通畅!!", e, ERROR.NETWORD_ERROR);
                return ex;
            }
            ex = new ResponeThrowable("网络连接不可用，请稍后重试!!", e, ((HttpException) e).code());
            return ex;
        } else if(e instanceof UnknownHostException) {
            ex = new ResponeThrowable("网络连接不可用，请稍后重试!!", e, ERROR.NETWORD_ERROR);
            return ex;
        } else if(e.getClass().getName().equals("io.reactivex.rxjava3.exceptions.CompositeException") ||
                e.getClass().getName().equals("io.reactivex.exceptions.CompositeException") ) {
            try {
                Method getExceptions = e.getClass().getDeclaredMethod("getExceptions");
                getExceptions.setAccessible(true);
                List<Throwable> exceptions = (List<Throwable>) getExceptions.invoke(e);
                if(exceptions == null || exceptions.isEmpty()) {
                    return new ResponeThrowable("请求失败", e, ERROR.HTTP_ERROR);
                }
                Throwable throwable = exceptions.get(0);
                if(throwable.getClass().getName().equals("com.violet.network.exception.NetException")) {
                    Field field = throwable.getClass().getDeclaredField("code");
                    field.setAccessible(true);
                    int code = field.getInt(throwable);
                    return new ResponeThrowable(throwable.getMessage(), e, code);
                }
                return new ResponeThrowable(exceptions.get(0).getMessage(), e, ERROR.HTTP_ERROR);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | NoSuchFieldException noSuchMethodException) {
                return new ResponeThrowable("请求失败", e, ERROR.HTTP_ERROR);
            }
        } else {
            ex = new ResponeThrowable(e.getMessage(), e, ERROR.UNKNOWN);
            return ex;
        }
    }


    /**
     * 约定异常
     */
    static class ERROR {
        /**
         * 未知错误
         */
        public static final int UNKNOWN = 1000;
        /**
         * 解析错误
         */
        public static final int PARSE_ERROR = 1001;
        /**
         * 网络错误
         */
        public static final int NETWORD_ERROR = 1002;
        /**
         * 协议出错
         */
        public static final int HTTP_ERROR = 1003;

        /**
         * 证书出错
         */
        public static final int SSL_ERROR = 1005;
    }

    public static class ResponeThrowable extends Exception {
        public int code;

        public ResponeThrowable(String message, Throwable throwable, int code) {
            super(message, throwable);
            this.code = code;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }
    }

    /**
     * ServerException发生后，将自动转换为ResponeThrowable返回
     */
    static class ServerException extends RuntimeException {
        int code;
        String message;
    }

}
